#include "v4l2.h"
std::vector<Buffer> global_buffers;
std::vector<v4l2_plane> planes;
int fd;

int v4l2_init(void){
    fd = open(VIDEO_DEVICE, O_RDWR);
    if (fd < 0) {
        std::cerr << "无法打开视频设备" << std::endl;
        return -1;
    }
    std::cout << "成功打开视频设备" << std::endl;

    // 查询设备属性
    struct v4l2_capability cap;
    memset(&cap, 0, sizeof(cap));
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
        std::cerr << "查询设备属性失败" << std::endl;
        close(fd);
        return -1;
    }
    std::cout << "驱动: " << cap.driver << "\t卡: " << cap.card << "\t总线: " << cap.bus_info << std::endl;

    // 检查视频捕获和流式传输能力
    if (!(cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE))) { //单平面或多平面
        std::cerr << "设备不支持视频捕获" << std::endl;
//        cleanup();
        return -1;
    }
    if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
        std::cerr << "设备不支持流式传输" << std::endl;
//        cleanup();
        return -1;
    }

    // 设置视频捕获格式（NV12，多平面）
    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    fmt.fmt.pix_mp.width = WIDTH;
    fmt.fmt.pix_mp.height = HEIGHT;
    fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_UYVY;
    fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
    fmt.fmt.pix_mp.num_planes = 1;
    fmt.fmt.pix_mp.plane_fmt[0].bytesperline = WIDTH * 2;
    fmt.fmt.pix_mp.plane_fmt[0].sizeimage = WIDTH * HEIGHT *  2;
    if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
        std::cerr << "设置视频格式失败: " << strerror(errno) << std::endl;
//        cleanup();
        return -1;
    }

    // 验证格式
    struct v4l2_format gfmt;
    memset(&gfmt, 0, sizeof(gfmt));
    gfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    if (ioctl(fd, VIDIOC_G_FMT, &gfmt) < 0) {
        std::cerr << "获取格式失败: " << strerror(errno) << std::endl;
//        cleanup();
        return -1;
    }
    std::cout << "格式: " << gfmt.fmt.pix_mp.width << "x" << gfmt.fmt.pix_mp.height
              << ", 像素格式: " << (char *)&gfmt.fmt.pix_mp.pixelformat
              << ", 平面数: " << (int)gfmt.fmt.pix_mp.num_planes << std::endl;

    // 申请缓冲区
    struct v4l2_requestbuffers req;
    memset(&req, 0, sizeof(req));
    req.count = NUM_BUFFERS;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
        std::cerr << "申请缓冲区失败: " << strerror(errno) << std::endl;
//        cleanup();
        return -1;
    }
    if (req.count < NUM_BUFFERS) {
        std::cerr << "警告: 实际分配缓冲区数 (" << req.count << ") 小于请求数 (" << NUM_BUFFERS << ")" << std::endl;
    }

    // 映射缓冲区
    global_buffers.resize(req.count);
    planes.resize(fmt.fmt.pix_mp.num_planes);
    for (unsigned int i = 0; i < req.count; i++) {
        struct v4l2_buffer buf;
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        buf.m.planes = planes.data();
        buf.length = planes.size();
        if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
            std::cerr << "查询缓冲区失败: " << strerror(errno) << std::endl;
//            cleanup();
            return -1;
        }

        global_buffers[i].length = buf.m.planes[0].length;
        global_buffers[i].start = mmap(NULL, buf.m.planes[0].length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.planes[0].m.mem_offset); //将摄像头每个平面的内存区域映射到用户空间的地址空间
        if (global_buffers[i].start == MAP_FAILED) {
            std::cerr << "内存映射失败: " << strerror(errno) << std::endl;
//            cleanup();
            return -1;
        }

        // 将缓冲区加入队列
        if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
            std::cerr << "缓冲区入队失败: " << strerror(errno) << std::endl;
//            cleanup();
            return -1;
        }
    }

    // 启动视频流
    enum v4l2_buf_type global_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;  //多平面捕获 V4L2缓冲区类型
    if (ioctl(fd, VIDIOC_STREAMON, &global_type) < 0) {
        std::cerr << "启动视频流失败: " << strerror(errno) << std::endl;
//        cleanup();
        return -1;
    }

    return 0;
}
